/**********************************
 * @Author: Ronnie Zhang
 * @LastEditor: Ronnie Zhang
 * @LastEditTime: 2023/12/07 20:23:54
 * @Email: zclzone@outlook.com
 * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
 **********************************/

import { Body, Controller, Get, Param, Post, Req, Res, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { JwtGuard, LocalGuard, PreviewGuard } from '@/common/guards';
import { ChangePasswordDto, RegisterUserDto } from './dto';
import { UserService } from '@/modules/user/user.service';
import * as svgCaptcha from 'svg-captcha';
import { CustomException, ErrorCode } from '@/common/exceptions/custom.exception';
import { ConfigService } from '@nestjs/config';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBody,
  ApiBearerAuth,
  ApiParam,
  ApiConsumes,
} from '@nestjs/swagger';

@ApiTags('认证')
@Controller('auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private userService: UserService,
    private configService: ConfigService,
  ) {}

  @UseGuards(LocalGuard)
  @Post('login')
  @ApiOperation({ summary: '用户登录', description: '用户通过用户名密码登录系统' })
  @ApiBody({
    description: '登录信息',
    schema: {
      type: 'object',
      properties: {
        username: { type: 'string', description: '用户名' },
        password: { type: 'string', description: '密码' },
        captcha: { type: 'string', description: '验证码' },
        isQuick: { type: 'boolean', description: '是否快速登录（预览模式）' },
      },
      required: ['username', 'password'],
    },
  })
  @ApiResponse({ status: 200, description: '登录成功' })
  @ApiResponse({ status: 401, description: '用户名或密码错误' })
  @ApiResponse({ status: 400, description: '验证码错误' })
  async login(@Req() req: any, @Body() body) {
    // 预览环境下可快速登录，不用验证码
    if (this.configService.get('IS_PREVIEW') === 'true' && body.isQuick) {
      return this.authService.login(req.user, req.session?.code);
    }
    // 判断验证码是否正确
    if (
      !req.session?.code ||
      req.session?.code?.toLocaleLowerCase() !== body.captcha?.toLocaleLowerCase()
    ) {
      throw new CustomException(ErrorCode.ERR_10003);
    }
    return this.authService.login(req.user, req.session?.code);
  }

  @Post('register')
  @UseGuards(PreviewGuard)
  @ApiOperation({ summary: '用户注册', description: '注册新用户（仅预览模式可用）' })
  @ApiBody({ type: RegisterUserDto, description: '用户注册信息' })
  @ApiResponse({ status: 201, description: '注册成功' })
  @ApiResponse({ status: 400, description: '注册信息有误' })
  @ApiResponse({ status: 403, description: '非预览模式，无法注册' })
  async register(@Body() user: RegisterUserDto) {
    return this.userService.create(user);
  }

  @Get('refresh/token')
  @UseGuards(JwtGuard)
  @ApiOperation({ summary: '刷新Token', description: '刷新用户访问令牌' })
  @ApiBearerAuth('JWT-auth')
  @ApiResponse({ status: 200, description: 'Token刷新成功' })
  @ApiResponse({ status: 401, description: 'Token无效或已过期' })
  async refreshToken(@Req() req: any) {
    return this.authService.generateToken(req.user);
  }

  @Post('current-role/switch/:roleCode')
  @UseGuards(JwtGuard)
  @ApiOperation({ summary: '切换角色', description: '切换用户当前激活的角色' })
  @ApiBearerAuth('JWT-auth')
  @ApiParam({ name: 'roleCode', description: '角色编码' })
  @ApiResponse({ status: 200, description: '角色切换成功' })
  @ApiResponse({ status: 401, description: 'Token无效或已过期' })
  @ApiResponse({ status: 403, description: '用户没有该角色权限' })
  async switchCurrentRole(@Req() req: any, @Param('roleCode') roleCode: string) {
    return this.authService.switchCurrentRole(req.user, roleCode);
  }

  @Post('logout')
  @UseGuards(JwtGuard)
  @ApiOperation({ summary: '用户登出', description: '用户登出系统，清除Token' })
  @ApiBearerAuth('JWT-auth')
  @ApiResponse({ status: 200, description: '登出成功' })
  @ApiResponse({ status: 401, description: 'Token无效或已过期' })
  async logout(@Req() req: any) {
    return this.authService.logout(req.user);
  }

  @Get('captcha')
  @ApiOperation({ summary: '获取验证码', description: '获取登录验证码图片' })
  @ApiResponse({ status: 200, description: '验证码图片（SVG格式）', content: { 'image/svg+xml': { schema: { type: 'string' } } } })
  async createCaptcha(@Req() req, @Res() res) {
    const captcha = svgCaptcha.create({
      size: 4,
      fontSize: 40,
      width: 80,
      height: 40,
      background: '#fff',
      color: true,
    });
    req.session.code = captcha.text || '';
    res.type('image/svg+xml');
    res.send(captcha.data);
  }

  @Post('password')
  @UseGuards(JwtGuard, PreviewGuard)
  @ApiOperation({ summary: '修改密码', description: '修改用户密码（仅预览模式可用）' })
  @ApiBearerAuth('JWT-auth')
  @ApiBody({ type: ChangePasswordDto, description: '密码修改信息' })
  @ApiResponse({ status: 200, description: '密码修改成功' })
  @ApiResponse({ status: 400, description: '原密码错误' })
  @ApiResponse({ status: 401, description: 'Token无效或已过期' })
  @ApiResponse({ status: 403, description: '非预览模式，无法修改密码' })
  async changePassword(@Req() req: any, @Body() body: ChangePasswordDto) {
    const ret = await this.authService.validateUser(req.user.username, body.oldPassword);
    if (!ret) {
      throw new CustomException(ErrorCode.ERR_10004);
    }
    // 修改密码
    await this.userService.resetPassword(req.user.id, body.newPassword);
    // 修改密码后退出登录
    await this.authService.logout(req.user);
    return true;
  }
}
